<template>
  <div id="uploader-container">
    <el-button
      type="primary"
      id="uploader-btn"
      @click="openUploadFile"
      :disabled="uploadFileList.length >= 1 && multi === false"
    >
      <label>
        上传{{btnName}}
        <span>({{size}}M)</span>
      </label>
      <i class="el-icon-upload el-icon--right"></i>
    </el-button>

    <input
      type="file"
      ref="fileToUpload"
      style="display:none"
      :accept="accept"
      :multiple="multi"
      @change="onFilesAdded"
    />

    <!-- 统一展示文件 -->
    <div class="file-list">
      <div class="item" v-for="(item, index) in uploadFileList" :key="index">
        <!-- 展示image -->
        <div class="icon" v-if="type === types.image">
          <img :src="item.url" width="60" height="60" />
        </div>

        <!-- 展示视频 -->
        <div class="icon" v-else-if="type === types.video">
          <img src="/static/img/uploader/video.png" height="24" />
        </div>

        <!-- 展示文件 -->
        <div class="icon" v-else-if="type === types.file">
          <img src="/static/img/uploader/file.png" height="24" />
        </div>

        <!-- 上传进度条 -->
        <div class="file-info">
          <div class="name">{{item.name}}</div>
          <div class="process">
            <el-progress v-if="item.process < 100" :percentage="item.process"></el-progress>
            <el-progress :percentage="100" v-else status="success"></el-progress>
          </div>
          <div class="action">
            <el-button type="text" @click="deleteFile(item.url)">删除</el-button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script>
import UploadFile from './UploadFile'
/*
    type: 表示上传文件类型
    multi: 是否允许上传多文件
    uploaded: 上传后的回调函数

    注：上传组件维护了已上传的列表，返回的数组中包括已上传的文件，也删除了已删除的文件。
    单文件上传返回 {url: 'http://xxx.com', name: 'xx.jpg'}
    多文件上传返回 [{url: 'xxx.com', name: 'xx.jpg'}]
  */
var fileExts = {
  image: '.jpg,.jpeg,.png',
  video: '.flv,.mp4,.mpeg',
  file: '.doc,.xls,.ppt,.pdf,.docx,.xlsx,.pptx,.txt'
}

function getExtName(url) {
  var arr = url.split('.')
  return arr[arr.length - 1]
}

export default {
  props: {
    type: {
      type: String,
      required: true
    },
    multi: {
      type: Boolean,
      required: false,
      default: () => false
    },
    fileList: {
      type: Array,
      required: false,
      default: () => []
    }
  },
  data() {
    return {
      accept: '',
      btnName: '',
      maxSize: {
        image: 2097152 /* 2M */,
        video: 629145600 /* 600M */,
        file: 20971520 /* 20M */
      },
      types: {
        image: 'image',
        video: 'video',
        file: 'file'
      },
      uploadFileList: []
    }
  },
  methods: {
    openUploadFile() {
      this.$refs.fileToUpload.click()
    },
    async getOSS() {
      let url = ''
      if (this.type === this.types.video) {
        url = '/sys/oss/videouptoken'
      } else if (this.type === this.types.image) {
        url = '/sys/oss/imguptoken'
      } else if (this.type === this.types.file) {
        url = '/sys/oss/filetoken'
      }
      let res = await this.$http({
        url: this.$http.adornUrl(url),
        method: 'post'
      })
      return res.data
    },
    async onFilesAdded(event) {
      let oss = await this.getOSS()
      let [token, domain, files] = [oss.token, oss.domain, event.target.files]

      let arrFile = [...files]
      for (const x of arrFile) {
        if (x.size > this.maxSize[this.type]) {
          let msg = x.name + '文件大小超出限制'
          this.$alert(msg, '上传失败')
          continue
        }

        var fileType = this.getFileType(x.name)
        const uploadFile = new UploadFile(x, token, domain, fileType === this.types.video)
        var upfile = {
          name: uploadFile.originFileName,
          type: fileType,
          url: '',
          process: 0
        }
        this.uploadFileList.push(upfile)
        uploadFile.upload({
          onProcess: process => {
            this.$set(upfile, 'process', process)
          },
          onSuccess: file => {
            console.log(file)
            this.$set(upfile, 'url', file.url)
            this.emitUploaded()
          },
          onError: _ => {
            this.$notify.error({ title: '失败', message: '上传文件失败' })
          }
        })
      }
      event.target.value = ''
    },
    getFileType(url) {
      var extName = '.' + getExtName(url)
      for (const key in fileExts) {
        if (fileExts.hasOwnProperty(key)) {
          const element = fileExts[key]
          if (element.indexOf(extName) > -1) {
            return this.types[key]
          }
        }
      }
      return this.types.file
    },
    emitUploaded() {
      if (this.multi) {
        let uploadedFiles = this.uploadFileList.map(x => ({
          url: x.url,
          name: x.name,
          type: x.type
        }))
        this.$emit('uploaded', uploadedFiles)
      } else {
        if (this.uploadFileList.length === 0) {
          this.$emit('uploaded', '')
        } else {
          let uploadedFile = this.uploadFileList[0]
          this.$emit('uploaded', {
            url: uploadedFile.url,
            name: uploadedFile.name,
            type: uploadedFile.type
          })
        }
      }
    },
    initAccept() {
      if (this.type === this.types.image) {
        this.btnName = '图片'
        this.accept = fileExts.image
      }

      if (this.type === this.types.video) {
        this.btnName = '视频'
        this.accept = fileExts.video
      }

      if (this.type === this.types.file) {
        this.btnName = '文件'
        this.accept = fileExts.file
      }
    },
    initUploadFileList() {
      this.$nextTick(() => {
        this.fileList.forEach(item => {
          if (!item) return true
          if (typeof item !== 'string') return true
          if (this.uploadFileList.some(x => x.url === item)) return true

          this.uploadFileList.push({
            name: name,
            url: item,
            type: this.getFileType(item),
            process: 100
          })
        })
      })
    },
    async deleteFile(url) {
      var confirm = await this.$confirm('您确认要删除这个文件吗？', '提示')
      if (confirm !== 'confirm') return

      let index = this.uploadFileList.findIndex(x => x.url === url)
      if (index > -1) this.uploadFileList.splice(index, 1)
      this.emitUploaded()
    },
    getFileByName(fileName) {
      let index = this.uploadFileList.findIndex(x => x.name === fileName)
      return index === -1 ? {} : this.uploadFileList[index]
    }
  },
  created() {
    this.initAccept()
  },
  watch: {
    fileList(val) {
      if (val && val.length === 0) {
        this.uploadFileList = []
      } else if (val && val.length > 0) {
        this.initUploadFileList()
      }
    }
  },
  computed: {
    size() {
      if (this.type === this.types.image) {
        return this.maxSize.image / 1024 / 1024
      }
      if (this.type === this.types.video) {
        return this.maxSize.video / 1024 / 1024
      }
      if (this.type === this.types.file) {
        return this.maxSize.file / 1024 / 1024
      }
    }
  }
}
</script>

<style lang="scss">
#uploader-container {
  #uploader-btn {
    margin: 0 0 10px 0;
  }

  .file-list {
    .item {
      display: inline-flex;
      align-items: center;
      padding: 5px 10px;
      margin-bottom: 10px;
      border-radius: 3px;

      &:hover {
        background: #eee;

        .action {
          visibility: visible;
        }
      }

      .icon {
        border-radius: 3px;
      }

      .file-info {
        margin-left: 10px;
        flex: auto;
        width: 200px;

        .name {
          white-space: nowrap;
          overflow: hidden;
          text-overflow: ellipsis;
        }
      }

      .action {
        color: #f56c6c;
        visibility: hidden;
      }
    }
  }
}
</style>
